// Effective C++ 条款29：为"异常安全"而努力是值得的
// 条款29讨论了C++中的异常安全性（Exception Safety），这是编写健壮代码的重要原则。

// 异常安全的基本概念
// 异常安全的函数在发生异常时能够：
// 1.不泄露资源
// 2.不破坏数据结构
// 3.保持程序处于一个有效的状态

// Scott Meyers在Effective C++中定义了三个异常安全保证级别：
// 1.基本保证（Basic Guarantee）：
//      如果异常被抛出，程序仍处于有效状态
//      不会有资源泄露
//      但对象的状态可能已经改变
// 2.强保证（Strong Guarantee）：
//      如果异常被抛出，程序状态不会改变
//      操作要么完全成功，要么完全失败（类似事务）
//      通常通过"copy-and-swap"策略实现
// 3.不抛异常保证（No-throw Guarantee）：
//      承诺绝不抛出异常
//      通常用于析构函数和内存释放操作
//      在C++11后用noexcept关键字标记

// 实现异常安全的关键技术
// 1. RAII（资源获取即初始化）
void someFunction()
{
    std::unique_ptr<Resource> res(new Resource()); // RAII
    // 即使下面的代码抛出异常，res也会被自动释放
    // ...
}

// 2. Copy-and-Swap策略
class Widget
{
private:
    std::string name;
    std::vector<int> data;

public:
    // 强异常安全保证的赋值操作符
    Widget &operator=(const Widget &rhs)
    {
        Widget temp(rhs); // 复制所有数据
        swap(temp);       // 不会抛出异常的操作
        return *this;
    }

    void swap(Widget &other) noexcept
    {
        name.swap(other.name);
        data.swap(other.data);
    }
};

// 3. 使用智能指针管理资源
class Widget
{
private:
    std::unique_ptr<Resource> pResource;
    // 而不是 Resource* pResource;
};

// 实际应用示例
// 考虑一个更复杂的场景：一个管理数据库连接池的类。这个例子将展示异常安全问题的多层次性：
class DatabaseConnectionPool
{
private:
    std::vector<DatabaseConnection *> availableConnections;
    std::map<int, DatabaseConnection *> activeConnections;
    mutable std::mutex connectionMutex;
    Logger *logger;
    Config *config;
    int maxConnections;

public:
    // 不安全版本
    DatabaseConnection *acquireConnection(int clientId)
    {
        std::lock_guard<std::mutex> lock(connectionMutex);

        if (availableConnections.empty())
        {
            if (activeConnections.size() >= maxConnections)
            {
                throw NoMoreConnectionsException();
            }

            DatabaseConnection *newConn = new DatabaseConnection(
                config->getServerAddress(),
                config->getCredentials()); // 可能抛出异常

            logger->logEvent("Created new connection"); // 可能抛出异常

            activeConnections[clientId] = newConn; // 可能抛出异常
            return newConn;
        }

        DatabaseConnection *conn = availableConnections.back();
        availableConnections.pop_back();

        if (!conn->ping())
        {                // 检查连接是否有效
            delete conn; // 删除无效连接

            conn = new DatabaseConnection(
                config->getServerAddress(),
                config->getCredentials()); // 可能抛出异常

            logger->logEvent("Replaced dead connection"); // 可能抛出异常
        }

        activeConnections[clientId] = conn; // 可能抛出异常
        return conn;
    }

    // 其他方法...
};
// 这个实现存在的问题：
// 1.资源泄漏：如果创建新连接后，logEvent或activeConnections[clientId] = newConn抛出异常，新创建的连接对象将泄漏
// 2.数据结构不一致：如果activeConnections[clientId] = conn抛出异常，连接已从availableConnections移除，但未添加到activeConnections
// 3.状态不一致：如果在替换死连接时发生异常，原连接已被删除，但新连接未成功创建或记录

// 异常安全版本的详细实现
class DatabaseConnectionPool
{
private:
    std::vector<std::unique_ptr<DatabaseConnection>> availableConnections;
    std::map<int, std::unique_ptr<DatabaseConnection>> activeConnections;
    mutable std::mutex connectionMutex;
    std::shared_ptr<Logger> logger;
    std::shared_ptr<Config> config;
    int maxConnections;

    // 辅助函数，创建新连接（强异常安全）
    std::unique_ptr<DatabaseConnection> createNewConnection()
    {
        // 所有可能抛出异常的操作集中在这里
        auto serverAddress = config->getServerAddress();
        auto credentials = config->getCredentials();
        return std::make_unique<DatabaseConnection>(serverAddress, credentials);
    }

public:
    // 异常安全版本
    std::unique_ptr<DatabaseConnection> acquireConnection(int clientId)
    {
        // 局部变量，用于实现"copy-and-swap"或"commit-or-rollback"语义
        std::unique_ptr<DatabaseConnection> connectionToReturn;

        // 使用RAII锁
        std::lock_guard<std::mutex> lock(connectionMutex);

        if (availableConnections.empty())
        {
            if (activeConnections.size() >= maxConnections)
            {
                throw NoMoreConnectionsException();
            }

            // 创建新连接（可能抛出异常，但不会有资源泄漏）
            connectionToReturn = createNewConnection();

            try
            {
                // 日志记录可能抛出异常
                logger->logEvent("Created new connection");

                // 准备所有状态变更，但尚未应用
                auto insertResult = activeConnections.insert(
                    std::make_pair(clientId, std::move(connectionToReturn)));

                // 如果插入成功，从map中获取连接的指针（所有权已转移到map）
                if (insertResult.second)
                {
                    // 创建一个新的unique_ptr，共享所有权（暂时）
                    connectionToReturn = std::unique_ptr<DatabaseConnection>(
                        insertResult.first->second.get(),
                        [](DatabaseConnection *) {} // 空删除器，因为真正的所有权在map中
                    );
                }
            }
            catch (...)
            {
                // 发生异常，connectionToReturn会自动释放资源
                // 数据结构保持一致
                throw;
            }
        }
        else
        {
            // 从可用连接池中获取连接
            // 使用移动语义避免不必要的复制
            connectionToReturn = std::move(availableConnections.back());
            availableConnections.pop_back();

            try
            {
                // 检查连接是否有效
                if (!connectionToReturn->ping())
                {
                    // 创建新连接替换无效连接
                    // 注意：旧连接会在connectionToReturn被重新赋值时自动释放
                    connectionToReturn = createNewConnection();
                    logger->logEvent("Replaced dead connection");
                }

                // 临时保存连接指针
                DatabaseConnection *rawConn = connectionToReturn.get();

                // 尝试将连接添加到活动连接映射
                auto insertResult = activeConnections.insert(
                    std::make_pair(clientId, std::move(connectionToReturn)));

                if (insertResult.second)
                {
                    // 创建一个新的unique_ptr，共享所有权（暂时）
                    connectionToReturn = std::unique_ptr<DatabaseConnection>(
                        rawConn,
                        [](DatabaseConnection *) {} // 空删除器
                    );
                }
                else
                {
                    // 客户端已有连接，处理冲突情况
                    // 将连接放回可用池
                    connectionToReturn = std::make_unique<DatabaseConnection>(rawConn);
                    availableConnections.push_back(std::move(connectionToReturn));

                    // 返回已存在的连接
                    auto &existingConn = insertResult.first->second;
                    connectionToReturn = std::unique_ptr<DatabaseConnection>(
                        existingConn.get(),
                        [](DatabaseConnection *) {});
                }
            }
            catch (...)
            {
                // 发生异常，将连接放回可用池（如果仍然有效）
                if (connectionToReturn && connectionToReturn->isValid())
                {
                    availableConnections.push_back(std::move(connectionToReturn));
                }
                // 否则connectionToReturn会自动释放资源
                throw;
            }
        }

        return connectionToReturn;
    }

    // 其他方法...
};

// 深入解析异常安全保证
// 1. 基本保证的实现细节
// 在上面的例子中，基本保证通过以下方式实现：
// 使用智能指针（std::unique_ptr）自动管理资源生命周期
// 在异常处理块中恢复数据结构的一致性
// 确保无论函数如何退出，都不会有资源泄漏

// 2. 强保证的实现策略
// 强保证通常通过以下策略实现：
// a. 事务性语义（Transactional Semantics）
class BankAccount
{
private:
    std::string accountNumber;
    double balance;
    std::vector<Transaction> history;

public:
    // 强异常安全保证
    void transfer(BankAccount &to, double amount)
    {
        // 保存原始状态
        double originalFromBalance = balance;
        double originalToBalance = to.balance;
        size_t originalHistorySize = history.size();
        size_t originalToHistorySize = to.history.size();

        try
        {
            // 执行转账操作
            if (amount > balance)
            {
                throw InsufficientFundsException();
            }

            balance -= amount;
            to.balance += amount;

            Transaction txn(TransactionType::DEBIT, amount,
                            "Transfer to " + to.accountNumber);
            history.push_back(txn);

            Transaction toTxn(TransactionType::CREDIT, amount,
                              "Transfer from " + accountNumber);
            to.history.push_back(toTxn);

            // 可能的数据库操作或其他可能抛出异常的操作
            updateDatabaseRecord();
            to.updateDatabaseRecord();
        }
        catch (...)
        {
            // 恢复原始状态
            balance = originalFromBalance;
            to.balance = originalToBalance;

            // 恢复历史记录
            history.resize(originalHistorySize);
            to.history.resize(originalToHistorySize);

            throw; // 重新抛出异常
        }
    }
};

// b. 复制-交换策略（Copy-and-Swap）
// 这种方法更为优雅，通常用于类的赋值操作符和需要修改多个成员的方法：
class NetworkPacket
{
private:
    std::vector<uint8_t> header;
    std::vector<uint8_t> payload;
    std::string protocol;
    uint32_t checksum;

    // 计算校验和（可能抛出异常）
    uint32_t calculateChecksum() const
    {
        // 复杂的校验和计算，可能抛出异常
        if (header.empty() || payload.empty())
        {
            throw InvalidPacketException();
        }

        // 复杂计算...
        return 0xABCDEF;
    }

public:
    void swap(NetworkPacket &other) noexcept
    {
        header.swap(other.header);
        payload.swap(other.payload);
        std::swap(protocol, other.protocol);
        std::swap(checksum, other.checksum);
    }

    // 强异常安全保证
    void updatePayload(const std::vector<uint8_t> &newPayload)
    {
        // 创建临时对象的副本
        NetworkPacket temp(*this);

        // 修改临时对象（可能抛出异常）
        temp.payload = newPayload;
        temp.checksum = temp.calculateChecksum();

        // 不会抛出异常的交换操作
        swap(temp);
        // 如果前面的步骤抛出异常，原对象保持不变
        // 如果成功，temp析构函数会清理旧状态
    }
};

// 3. 不抛出异常保证的实现
// 某些关键操作必须提供不抛出异常保证，特别是析构函数和移动操作：
class CriticalResource
{
private:
    void *rawMemory;
    size_t size;

public:
    // 移动构造函数不抛出异常
    CriticalResource(CriticalResource &&other) noexcept
        : rawMemory(other.rawMemory), size(other.size)
    {
        other.rawMemory = nullptr;
        other.size = 0;
    }

    // 移动赋值操作符不抛出异常
    CriticalResource &operator=(CriticalResource &&other) noexcept
    {
        if (this != &other)
        {
            // 释放当前资源
            deallocate();

            // 获取other的资源
            rawMemory = other.rawMemory;
            size = other.size;

            // 重置other
            other.rawMemory = nullptr;
            other.size = 0;
        }
        return *this;
    }

    // 析构函数不抛出异常
    ~CriticalResource() noexcept
    {
        try
        {
            deallocate();
        }
        catch (...)
        {
            // 记录错误但不传播异常
            std::cerr << "Error during resource deallocation" << std::endl;
        }
    }

private:
    void deallocate()
    {
        if (rawMemory)
        {
            free(rawMemory);
            rawMemory = nullptr;
            size = 0;
        }
    }
};

// 异常安全与性能的权衡
// 在实际项目中，异常安全与性能之间存在权衡：
class LargeDataProcessor
{
private:
    std::vector<double> hugeDataSet; // 可能包含数百万个元素

public:
    // 基本异常安全保证版本（性能更好）
    void processInPlace()
    {
        for (auto &value : hugeDataSet)
        {
            // 直接修改数据（如果抛出异常，部分数据已被修改）
            value = complexCalculation(value);
        }
    }

    // 强异常安全保证版本（性能较差）
    void processWithStrongGuarantee()
    {
        // 创建完整副本（内存和CPU开销大）
        std::vector<double> tempData = hugeDataSet;

        for (auto &value : tempData)
        {
            value = complexCalculation(value);
        }

        // 原子交换（不会抛出异常）
        hugeDataSet.swap(tempData);
    }

    // 折中方案：分批处理，每批提供强保证
    void processByBatches(size_t batchSize = 1000)
    {
        for (size_t i = 0; i < hugeDataSet.size(); i += batchSize)
        {
            // 确定当前批次的大小
            size_t currentBatchSize = std::min(batchSize, hugeDataSet.size() - i);

            // 创建当前批次的副本
            std::vector<double> batchCopy(
                hugeDataSet.begin() + i,
                hugeDataSet.begin() + i + currentBatchSize);

            // 处理副本
            for (auto &value : batchCopy)
            {
                value = complexCalculation(value);
            }

            // 将处理后的批次复制回原数据
            std::copy(batchCopy.begin(), batchCopy.end(), hugeDataSet.begin() + i);

            // 如果发生异常，只有当前批次之前的数据被修改
        }
    }
};

// 实际项目中的异常安全策略
// 在大型项目中，通常会定义明确的异常安全策略：
// 1.关键路径：提供强异常安全保证
// 2.性能敏感路径：提供基本异常安全保证
// 3.资源管理：始终使用RAII和智能指针
// 4.异常中立：大多数函数应该是异常中立的，即传播它们遇到的异常
// 5.异常规范：明确定义哪些函数可能抛出异常，哪些不会
// 总结
// 条款29的核心是：异常安全不仅仅是防止程序崩溃，而是确保程序在面对异常时仍然保持一致性和可靠性。虽然实现高级别的异常安全需要额外的工作和可能的性能开销，但这种投资通常是值得的，特别是在开发长期运行的系统、处理重要数据或需要高可靠性的应用程序时。
// 通过使用现代C++的工具（智能指针、RAII、移动语义）和设计模式（复制-交换、事务性语义），可以在不牺牲太多性能的情况下实现良好的异常安全性。